import joi from 'joi';
import fs from 'node:fs';
import dayjs from 'dayjs';
import path from 'node:path';
import { AnyKey } from '@p/utils';
import { debounce } from '@e/methods/tool';
import { getVarType } from '@e/methods/type';
import { ConfigFile } from '@p/main-config-file';

/**
 * 配置文件默认值
 */
export const configFileDefaultValue: ConfigFile = {
	base: {
		defaultColorMode: 'follow-system',
	},
};

/**
 * 配置文件的验证对象
 */
const schema = joi
	.object({
		base: joi
			.object({
				defaultColorMode: joi.string().valid('follow-system', 'dark', 'light').required(),
			})
			.required(),
	})
	.required();

/**
 * 检查配置文件的值
 */
export function checkConfigFileValue(value: ConfigFile) {
	const result = schema.validate(value);

	if (result.error) {
		return false;
	} else {
		return true;
	}
}

/**
 * 初始化配置文件
 */
export function initConfigFile(dirPath: string) {
	const filePath = path.join(dirPath, 'config.json');
	var value: ConfigFile;
	let isCheck = false;

	function fn<T>(obj1: T, obj2: T): T {
		const _obj1 = JSON.parse(JSON.stringify(obj1));
		const _obj2 = JSON.parse(JSON.stringify(obj2));

		const keys1 = Object.keys(_obj1);
		const keys2 = Object.keys(_obj2);

		keys2.forEach((t) => {
			if (!keys1.some((v) => v === t)) {
				delete _obj2[t];
			}
		});

		keys1.forEach((t) => {
			if (!keys2.some((v) => v === t)) {
				_obj2[t] = _obj1[t];
			} else {
				if (getVarType(_obj1[t]) === 'object') {
					_obj2[t] = fn(_obj1[t], _obj2[t]);
				}
			}
		});

		return _obj2;
	}

	function watch<T>(obj: T, callback: Function): T {
		for (const key in obj) {
			if (typeof obj[key] === 'object') {
				obj[key] = watch(obj[key], callback);
			}
		}

		const _proxy = new Proxy(obj as AnyKey<any>, {
			get(traget, prop) {
				return traget[prop as string];
			},
			set(target, prop, newValue) {
				target[prop as string] = newValue;

				callback();

				return true;
			},
			deleteProperty() {
				return false;
			},
		});

		return _proxy as T;
	}

	if (fs.existsSync(filePath)) {
		try {
			value = JSON.parse(fs.readFileSync(filePath, 'utf-8'));

			isCheck = true;
		} catch (error) {
			throw error;
		}
	} else {
		try {
			const str = JSON.stringify(configFileDefaultValue, null, '\t');

			fs.writeFileSync(filePath, str, 'utf-8');

			value = configFileDefaultValue;
		} catch (error) {
			throw error;
		}
	}

	if (isCheck) {
		value = fn(configFileDefaultValue, value);
	}

	const ff = debounce(() => {
		try {
			const str = JSON.stringify(value, null, '\t');

			fs.writeFileSync(filePath, str, 'utf-8');

			console.log(dayjs().format('HH:mm:ss'), '配置文件更改', '\n', str);
		} catch (error) {
			throw error;
		}
	}, 100);

	return watch(value, ff);
}
